/**
 * 导出数据的结构定义
 * 键为对象存储空间名称，值为包含键和值的对象数组
 */
export interface ExportedData {
  [storeName: string]: Array<{
    key: IDBValidKey
    value: any
  }>
}

/**
 * 导出IndexedDB数据库的所有数据
 * @param dbName - 数据库名称
 * @returns {Promise<ExportedData>} 包含所有数据的Promise对象
 */
export const exportIndexedDB = (dbName: string): Promise<ExportedData> => {
  return new Promise((resolve, reject) => {
    // 打开数据库
    const request: IDBOpenDBRequest = indexedDB.open(dbName)
    const exportData: ExportedData = {}

    request.onerror = (event: Event) => {
      const error = (event.target as IDBOpenDBRequest).error
      console.error('打开数据库失败:', error)
      reject(error)
    }

    request.onsuccess = (event: Event) => {
      const db: IDBDatabase = (event.target as IDBOpenDBRequest).result
      const transaction: IDBTransaction = db.transaction(
        Array.from(db.objectStoreNames),
        'readonly',
      )

      // 遍历所有对象存储空间
      Array.from(db.objectStoreNames).forEach((storeName: string) => {
        exportData[storeName] = []
        const store: IDBObjectStore = transaction.objectStore(storeName)

        // 打开游标遍历所有数据
        const cursorRequest: IDBRequest = store.openCursor()

        cursorRequest.onsuccess = (cursorEvent: Event) => {
          const cursor: IDBCursorWithValue | null = (cursorEvent.target as IDBRequest).result
          if (cursor) {
            // 将数据添加到导出对象
            exportData[storeName].push({
              key: cursor.key,
              value: cursor.value,
            })
            cursor.continue()
          }
        }

        cursorRequest.onerror = (cursorEvent: Event) => {
          const error = (cursorEvent.target as IDBRequest).error
          console.error(`遍历存储空间 ${storeName} 失败:`, error)
          reject(error)
        }
      })

      // 事务完成时解析Promise
      transaction.oncomplete = () => {
        db.close()
        resolve(exportData)
      }

      transaction.onerror = (event: Event) => {
        const error = (event.target as IDBTransaction).error
        console.error('事务处理失败:', error)
        reject(error)
      }
    }

    // 处理数据库版本变更
    request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
      // 如果数据库版本需要更新，我们仍然可以导出当前版本的数据
      ;(event.target as IDBOpenDBRequest).transaction!.abort()
      const oldVersionDb: IDBDatabase = (event.target as IDBOpenDBRequest).result
      oldVersionDb.close()

      // 用旧版本重新打开
      indexedDB.open(dbName, event.oldVersion).onsuccess = (e: Event) => {
        const db: IDBDatabase = (e.target as IDBOpenDBRequest).result
        const transaction: IDBTransaction = db.transaction(
          Array.from(db.objectStoreNames),
          'readonly',
        )

        Array.from(db.objectStoreNames).forEach((storeName: string) => {
          exportData[storeName] = []
          const store: IDBObjectStore = transaction.objectStore(storeName)
          const cursorRequest: IDBRequest = store.openCursor()

          cursorRequest.onsuccess = (cursorEvent: Event) => {
            const cursor: IDBCursorWithValue | null = (cursorEvent.target as IDBRequest).result
            if (cursor) {
              exportData[storeName].push({
                key: cursor.key,
                value: cursor.value,
              })
              cursor.continue()
            }
          }

          cursorRequest.onerror = (cursorEvent: Event) => {
            const error = (cursorEvent.target as IDBRequest).error
            console.error(`遍历旧版本存储空间 ${storeName} 失败:`, error)
            reject(error)
          }
        })

        transaction.oncomplete = () => {
          db.close()
          resolve(exportData)
        }

        transaction.onerror = (event: Event) => {
          const error = (event.target as IDBTransaction).error
          console.error('旧版本数据库事务处理失败:', error)
          reject(error)
        }
      }

      indexedDB.open(dbName, event.oldVersion).onerror = (e: Event) => {
        const error = (e.target as IDBOpenDBRequest).error
        console.error('打开旧版本数据库失败:', error)
        reject(error)
      }
    }
  })
}

/**
 * 将数据导入到IndexedDB数据库
 * @param dbName - 数据库名称
 * @param data - 要导入的数据
 * @param clearExisting - 是否清除现有数据（默认为true）
 * @returns {Promise<void>} 导入完成的Promise
 */
export const importIndexedDB = (
  dbName: string,
  data: ExportedData,
  clearExisting: boolean = true,
): Promise<void> => {
  return new Promise((resolve, reject) => {
    // 打开数据库，如果不存在则创建
    const request: IDBOpenDBRequest = indexedDB.open(dbName)
    let db: IDBDatabase

    // 处理数据库版本升级
    request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
      db = (event.target as IDBOpenDBRequest).result

      // 创建所有需要的对象存储空间
      Object.keys(data).forEach((storeName) => {
        if (!db.objectStoreNames.contains(storeName)) {
          // 假设数据使用code作为主键
          db.createObjectStore(storeName, { keyPath: 'code' })
        }
      })
    }

    request.onerror = (event: Event) => {
      const error = (event.target as IDBOpenDBRequest).error
      console.error('打开数据库失败:', error)
      reject(error)
    }

    request.onsuccess = (event: Event) => {
      db = (event.target as IDBOpenDBRequest).result
      const transaction: IDBTransaction = db.transaction(
        Array.from(db.objectStoreNames),
        'readwrite',
      )

      // 处理每个对象存储空间
      Object.keys(data).forEach((storeName) => {
        if (!db.objectStoreNames.contains(storeName)) {
          console.warn(`对象存储空间 ${storeName} 不存在，已跳过`)
          return
        }

        const store: IDBObjectStore = transaction.objectStore(storeName)
        // 检查对象存储空间是否使用内联键
        const usesInlineKeys = !!store.keyPath

        // 清除现有数据（如果需要）
        if (clearExisting) {
          const clearRequest = store.clear()
          clearRequest.onerror = (e) => {
            console.error(`清除存储空间 ${storeName} 失败:`, (e.target as IDBRequest).error)
            reject((e.target as IDBRequest).error)
          }
        }

        // 导入新数据
        data[storeName].forEach(({ key, value }) => {
          try {
            // 关键修复：如果使用内联键，不传递key参数
            const addRequest = usesInlineKeys ? store.put(value) : store.put(value, key)
            addRequest.onerror = (e) => {
              console.error(`插入数据到 ${storeName} 失败:`, (e.target as IDBRequest).error)
              reject((e.target as IDBRequest).error)
            }
          } catch (error) {
            console.error(`处理 ${storeName} 中的数据时出错:`, error)
            reject(error)
          }
        })
      })

      // 处理事务完成
      transaction.oncomplete = () => {
        db.close()
        resolve()
      }

      transaction.onerror = (event: Event) => {
        const error = (event.target as IDBTransaction).error
        console.error('导入事务失败:', error)
        reject(error)
      }
    }
  })
}

/**
 * 将数据导出为JSON文件并下载
 * @param data - 要导出的数据
 * @param fileName - 导出的文件名
 */
export const downloadJSON = (data: ExportedData, fileName?: string): void => {
  try {
    const jsonString: string = JSON.stringify(data, null, 2)
    const blob: Blob = new Blob([jsonString], { type: 'application/json' })
    const url: string = URL.createObjectURL(blob)

    const a: HTMLAnchorElement = document.createElement('a')
    a.href = url
    a.download = fileName || 'indexedDB-export.json'
    document.body.appendChild(a)
    a.click()

    // 清理
    setTimeout(() => {
      document.body.removeChild(a)
      URL.revokeObjectURL(url)
    }, 0)
  } catch (error) {
    console.error('下载JSON文件失败:', error)
    throw error
  }
}

/**
 * 从上传的文件中读取JSON数据
 * @param file - 上传的文件对象
 * @returns {Promise<ExportedData>} 解析后的JSON数据
 */
export const readJSONFile = (file: File): Promise<ExportedData> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()

    reader.onload = (event) => {
      try {
        const content = event.target?.result as string
        const data = JSON.parse(content) as ExportedData
        resolve(data)
      } catch (error) {
        console.error('解析JSON文件失败:', error)
        reject(error)
      }
    }

    reader.onerror = () => {
      console.error('读取文件失败:', reader.error)
      reject(reader.error)
    }

    reader.readAsText(file)
  })
}

// ===== 投资数据库特定功能 =====

/**
 * 导出投资数据库指定表的数据
 * @param storeName - 表名称 ('funds' 或 'stocks')
 * @returns {Promise<ExportedData>} 包含指定表数据的Promise对象
 */
export const exportInvestmentDB = (storeName: 'funds' | 'stocks'): Promise<ExportedData> => {
  return new Promise((resolve, reject) => {
    // 打开数据库
    const request: IDBOpenDBRequest = indexedDB.open('InvestmentDB')
    const exportData: ExportedData = {}

    request.onerror = (event: Event) => {
      const error = (event.target as IDBOpenDBRequest).error
      console.error('打开数据库失败:', error)
      reject(error)
    }

    request.onsuccess = (event: Event) => {
      const db: IDBDatabase = (event.target as IDBOpenDBRequest).result
      const transaction: IDBTransaction = db.transaction([storeName], 'readonly')

      exportData[storeName] = []
      const store: IDBObjectStore = transaction.objectStore(storeName)

      // 打开游标遍历所有数据
      const cursorRequest: IDBRequest = store.openCursor()

      cursorRequest.onsuccess = (cursorEvent: Event) => {
        const cursor: IDBCursorWithValue | null = (cursorEvent.target as IDBRequest).result
        if (cursor) {
          // 将数据添加到导出对象
          exportData[storeName].push({
            key: cursor.key,
            value: cursor.value,
          })
          cursor.continue()
        }
      }

      cursorRequest.onerror = (cursorEvent: Event) => {
        const error = (cursorEvent.target as IDBRequest).error
        console.error(`遍历存储空间 ${storeName} 失败:`, error)
        reject(error)
      }

      // 事务完成时解析Promise
      transaction.oncomplete = () => {
        db.close()
        resolve(exportData)
      }

      transaction.onerror = (event: Event) => {
        const error = (event.target as IDBTransaction).error
        console.error('事务处理失败:', error)
        reject(error)
      }
    }
  })
}

/**
 * 导入数据到投资数据库指定表
 * @param storeName - 表名称 ('funds' 或 'stocks')
 * @param data - 要导入的数据
 * @param clearExisting - 是否清除现有数据（默认为true）
 * @returns {Promise<void>} 导入完成的Promise
 */
export const importInvestmentDB = (
  storeName: 'funds' | 'stocks',
  data: ExportedData,
  clearExisting: boolean = true,
): Promise<void> => {
  return new Promise((resolve, reject) => {
    // 打开数据库
    const request: IDBOpenDBRequest = indexedDB.open('InvestmentDB')
    let db: IDBDatabase

    // 处理数据库版本升级
    request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
      db = (event.target as IDBOpenDBRequest).result

      // 创建需要的对象存储空间
      if (!db.objectStoreNames.contains(storeName)) {
        // 假设数据使用code作为主键
        db.createObjectStore(storeName, { keyPath: 'code' })
      }
    }

    request.onerror = (event: Event) => {
      const error = (event.target as IDBOpenDBRequest).error
      console.error('打开数据库失败:', error)
      reject(error)
    }

    request.onsuccess = (event: Event) => {
      db = (event.target as IDBOpenDBRequest).result
      const transaction: IDBTransaction = db.transaction([storeName], 'readwrite')

      if (!db.objectStoreNames.contains(storeName)) {
        console.warn(`对象存储空间 ${storeName} 不存在，已跳过`)
        db.close()
        resolve()
        return
      }

      const store: IDBObjectStore = transaction.objectStore(storeName)
      // 检查对象存储空间是否使用内联键
      const usesInlineKeys = !!store.keyPath

      // 清除现有数据（如果需要）
      if (clearExisting) {
        const clearRequest = store.clear()
        clearRequest.onerror = (e) => {
          console.error(`清除存储空间 ${storeName} 失败:`, (e.target as IDBRequest).error)
          reject((e.target as IDBRequest).error)
        }
      }

      // 导入新数据 - 只导入指定表的数据
      if (data[storeName]) {
        data[storeName].forEach(({ key, value }) => {
          try {
            // 关键修复：如果使用内联键，不传递key参数
            const addRequest = usesInlineKeys ? store.put(value) : store.put(value, key)
            addRequest.onerror = (e) => {
              console.error(`插入数据到 ${storeName} 失败:`, (e.target as IDBRequest).error)
              reject((e.target as IDBRequest).error)
            }
          } catch (error) {
            console.error(`处理 ${storeName} 中的数据时出错:`, error)
            reject(error)
          }
        })
      }

      // 处理事务完成
      transaction.oncomplete = () => {
        db.close()
        resolve()
      }

      transaction.onerror = (event: Event) => {
        const error = (event.target as IDBTransaction).error
        console.error('导入事务失败:', error)
        reject(error)
      }
    }
  })
}
